﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Timers;
using System.Threading;

namespace WcfServiceApplication
{
    public class KalamburyGame : IKalamburyGame
    {
        System.Timers.Timer timer_clearAll;

        static List<Room> _rooms = new List<Room>();
        static List<User> _users = new List<User>();

        public KeyValuePair<CreateUserStaus, User> NewUser(string name)
        {
            foreach (string u in _users.Select(u => u.Name.ToLower()))
                if (u == name.ToLower())
                    return new KeyValuePair<CreateUserStaus, User>(CreateUserStaus.UserExists, null);

            User newuser = new User(name);
            _users.Add(newuser);
            return new KeyValuePair<CreateUserStaus, User>(CreateUserStaus.OK, newuser);
        }
        public void ResetRoom(User user)
        {
            var room = FindUserRoom(user);
            if (room != null)
                room.Reset();
        }

        public List<string> GetRoomsNames()
        {
            return (from el in _rooms
                    select el.Name).ToList<string>();

        }

        public void QuitRoom(User user)
        {
            var room = FindUserRoom(user);
            if (room != null)
                room.RemoveUser(user);
        }

        public string GetAnswer(User user)
        {
            return FindUserRoom(user).CurrentAnswer;
        }

        public List<User> GetUserFromMyRoom(User user)
        {
            var room = FindUserRoom(user);
            if (room != null)
                return room.Users;
            else
                return new List<User>();
        }

        public bool CreateRoom(User user, string name) //TODO
        {

            foreach (var r in _rooms)
            {
                if (r.Name.ToLower() == name.ToLower())
                    return false;
            }
            _rooms.Add(new Room(name));
            return true;
        }

        public string GetMessages(User user)
        {
            var room = FindUserRoom(user);
            if (room != null)
            {
               return room.GetMessage();
            }
            return String.Empty;
        }

        public JoinResult JoinRoom(User user, string roomName)
        {
            foreach (var room in _rooms)
            {
                if (room.Name == roomName)
                    return room.JoinUser(user);
            }
            return JoinResult.Fail;
        }

        public User WhoWin(User user)
        {
            return FindUserRoom(user).LastWinner;
        }

        public bool CheckAnswer(User user, string answer)
        {
            bool reset = false;
            var _room = FindUserRoom(user);
            if (_room != null)
            {
                if (_room.CurrentAnswer.ToLower() == answer.ToLower())
                {
                    _room.GameStat = GameStatus.EndSmbKnown;
                    _room.AddMessage("", String.Format("{0} guessed, answer: {1}", user.Name, _room.CurrentAnswer));
                    _room.LastWinner = user;
                    _room.AddPoints(_room.Painter, 20);
                    _room.AddPoints(user, 100);
                    _room.NextPainter();
                    _room.SetNewAnswer();
                    _room.NewImage(ClearImage.ClearImageInString);
                    _room.SetNoReady();
                }
                _room.AddMessage(user.Name, answer);
            }
            return false;
        }
        public void Clear(string psw)
        {
            if (psw == "projektkomponentoweXYZ")
            {
                _users = new List<User>();
            }
        }

        public void Ialive(User user)
        {
            var room = FindUserRoom(user);
            if (room != null)
            {
                var usr = room.Users.Where(e => e.Name == user.Name).Select(e => e).First();
                if (usr != null)
                    usr.Ialive();

            }
        }

        public StartedGameStatus StartGame(User user)
        {
            //check are everyone is ready 
            var room = FindUserRoom(user);
            if (room == null)
                return StartedGameStatus.NotEnoughPlayers;
            if (room.GameStat == GameStatus.During)
                return StartedGameStatus.Start;
            if (room.Users.Count < 2)
                return StartedGameStatus.NotEnoughPlayers;
            SetReady(true, user);
            bool EveryOneReady = true;
            foreach (bool el in room.Users.Select(e => e.Ready))
            {
                if (el == false)
                {
                    EveryOneReady = false;
                    break;
                }
            }
            if (EveryOneReady == false)
            {
                room.GameStat = GameStatus.Wait;
                return StartedGameStatus.WaitingUntilAllPushTheStart;
            }
            else
            {
                room.GameStat = GameStatus.During;
                return StartedGameStatus.Start;
            }

        }

        public GameStatus GetStatus(User user)
        {
            var r = FindUserRoom(user);
            if (r != null)
                return r.GetStatus();
            else
                return GameStatus.NoRoom;
        }

        public CurrentImage IsNewImage(User user, Guid imageGuid)
        {
            var room = FindUserRoom(user);

            if (room == null)
                return new CurrentImage();
            if (room.CurImage.Guid != imageGuid)
            {
                return room.CurImage;
            }
            else
                return new CurrentImage();
        }

        public void NewImage(User user, string Image)
        {
            var r = FindUserRoom(user);
            if (r !=null)
                r.NewImage(Image);
        }

        public string GetImage(User user)
        {
            var r = FindUserRoom(user);
            if (r != null)
                return r.CurImage.ImageInString;
            else
                return ClearImage.ClearImageInString;
        }

        private Room FindUserRoom(User user)
        {
            foreach (Room room in _rooms)
            {
                if (IsRoomContainsUser(user, room))
                    return room;
            }
            return null;
        }

        public User GetPainter(User user)
        {
            var r = FindUserRoom(user);
            if (r != null)
                return FindUserRoom(user).Painter;
            else
                return user; //TODO

        }

        private void SetReady(bool value, User user)
        {
            var room = FindUserRoom(user);
            foreach (User usr in room.Users)
            {
                if (usr.Name == user.Name)
                {
                    usr.Ready = value;
                    break;
                }
            }
        }

        private bool IsRoomContainsUser(User user, Room room)
        {
            foreach (User usr in room.Users)
                if (usr.Name == user.Name) //TODO GUID
                    return true;
            return false;
        }

        object clearGuard = new object();
        private KalamburyGame()
        {
            lock (clearGuard)
            {
                if (timer_clearAll == null)
                {
                    timer_clearAll = new System.Timers.Timer() { AutoReset = false, Enabled = true, Interval = 5000 };
                    timer_clearAll.Elapsed += new ElapsedEventHandler((s, ea) =>
                    {
                        timer_clearAll.Enabled = false;
                        timer_clearAll.Stop();
                        List<Room> roomToRemove = new List<Room>();
                        try
                        {
                            foreach (var r in _rooms)
                            {
                                
                                List<User> userToRemove = new List<User>();
                                foreach (User u in r.Users)
                                    if (DateTime.Now.TimeOfDay - u.LastNotification.TimeOfDay > new TimeSpan(0, 0, 20) && u.LastNotification.Date.Year > 2011)
                                        userToRemove.Add(u);
                                foreach (User u in userToRemove)
                                {
                                    r.RemoveUser(u);
//                                    var usr = _users.Where(b => b.Name == u.Name).Select(e => e);
                                }
                                if (r.Users.Count == 0 && DateTime.Now - r.CreationTime > new TimeSpan(0, 0, 30))
                                    roomToRemove.Add(r);
                            }
                            foreach (Room r in roomToRemove)
                                _rooms.Remove(r);
                            
                            
                        }
                        catch (InvalidOperationException) { }
                        catch (ArgumentOutOfRangeException) { }
                        timer_clearAll.Enabled = true;
                        timer_clearAll.Start();
                    });
                }
            }
        }

    }
}
